package com.zeedev.flyingsaucer.modules.BeerDatabaseModule.impl.stores;

import android.app.Activity;
import android.content.ContentQueryMap;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.net.Uri.Builder;
import android.provider.BaseColumns;
import android.util.Log;
import android.widget.Toast;
import com.google.inject.Inject;
import com.zeedev.flyingsaucer.data.BeerUri;
import com.zeedev.flyingsaucer.modules.BeerDatabaseModule.interfaces.ListModel;
import mobi.zeedev.flyingsaucer.common.DataModule.BeerConstants;
import mobi.zeedev.flyingsaucer.common.DataModule.FlyingSaucerConv;
import mobi.zeedev.flyingsaucer.common.DataModule.FlyingSaucerConv.Beers;
import mobi.zeedev.flyingsaucer.common.DataModule.FlyingSaucerConv.Stores;
import mobi.zeedev.flyingsaucer.common.DataModule.FlyingSaucerConv.Stores.StoreBeer;
import mobi.zeedev.flyingsaucer.common.DataModule.Util;
import mobi.zeedev.flyingsaucer.common.RegexModule.RegexUtil;
import mobi.zeedev.flyingsaucer.common.WebLinkModule.interfaces.UfoClubClient;
import roboguice.inject.InjectExtra;
import roboguice.util.Ln;

import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;

//import android.util.Log;

public class StoreBeerListModel extends Observable implements Serializable, ListModel {

    public static final String TAG = "BeerListModel";

    @InjectExtra(BeerConstants.INTENT_STORE_URL)
    String storeUrl;

    Long storeDbId;

    @Inject
    Activity mActivity;

    @Inject
    ContentResolver mContentResolver;

    @Inject
    public StoreBeerListModel() {
        super();

//        this.controller = controller;

//        Intent intent = ((Activity) this.controller.getParent()).getIntent();
//        this.storeUrl = intent.getStringExtra(BeerConstants.INTENT_STORE_URL);

//        mContext = this.controller.getParent().getContext();


//        mContentResolver = mContext.getContentResolver();

        this.storeDbId = StoreBeerListModel.getStoreDbIdV2(mActivity, storeUrl);

        this.beerUri = this.getDefaultBeerUri();

    }

    @Override
    public void destroy() {
        //TODO ??? close download?
        //do nothing
//		((UfoClubApp)((Activity) mContext).getApplication()).setStoreBeersDownloader(null);
    }

    //StoresPreferencesModel Refresh

    @Inject
    UfoClubClient beerWebLink;

    @Override
    public void masterRefresh() {
        String stylesUrl = storeUrl + "?groupby=style";
        String brewerUrl = storeUrl + "?groupby=brewer";
        List<Map<String, Object>> stylesResult = null;
        List<Map<String, Object>> brewerResult = null;

        try {
            stylesResult = beerWebLink.getStoresBeersByCategory(stylesUrl);
        } catch (Exception e) {
            Ln.e(e);
//            e.printStackTrace();
//            StoreBeerListModel.this.controller.getParent().sayToast("There was an error downloading the beer list.");
            Toast.makeText(mActivity, "There was an error downloading the beer list.", Toast.LENGTH_SHORT).show();
        }
        try {
            brewerResult = beerWebLink.getStoresBeersByCategory(brewerUrl);
        } catch (Exception e) {
//            e.printStackTrace();
            Ln.e(e);
//            StoreBeerListModel.this.controller.getParent().sayToast("There was an error downloading the beer list.");
            Toast.makeText(mActivity, "There was an error downloading the beer list.", Toast.LENGTH_SHORT).show();
        }

        if (shouldCancel()) {
            return;
        }

        List<Map<String, Object>> lmStyles = getUnfoldedBeerList(stylesResult, Beers.STYLE_NAME);
        List<Map<String, Object>> lmBrewer = getUnfoldedBeerList(brewerResult, Beers.BREWER_NAME);

        List<ContentValues> cvListStyles = null;
        List<ContentValues> cvListBrewers = null;

        try {
            cvListStyles = RegexUtil.induceContentValuesList(lmStyles);

        } catch (Exception e) {
//            StoreBeerListModel.this.controller.getParent().sayToast("There was an error parsing the beer list.");
            Ln.w(e);
            Toast.makeText(mActivity, "There was an error parsing the beer list.", Toast.LENGTH_SHORT).show();

        }
        try {
            cvListBrewers = RegexUtil.induceContentValuesList(lmBrewer);
        } catch (Exception e) {
//            StoreBeerListModel.this.controller.getParent().sayToast("There was an error parsing the beer list.");
            Ln.w(e);
            Toast.makeText(mActivity, "There was an error parsing the beer list.", Toast.LENGTH_SHORT).show();
        }

        if (shouldCancel()) {
            return;
        }


        Map<String, ContentValues> keyMapO = Util.generateKeyMap(cvListStyles, Beers.BEER_ID, String.class);

        for (ContentValues cv : cvListBrewers) {//Entry<String, ContentValues> entry : keyMapO.entrySet()
            String brewerName = cv.getAsString(Beers.BREWER_NAME);
            String beerId = cv.getAsString(Beers.BEER_ID);
            if (brewerName != null) {
                ContentValues cvStyleBeer = keyMapO.get(beerId);
                cvStyleBeer.put(Beers.BREWER_NAME, brewerName);
            }

        }

        List<ContentValues> result = cvListStyles;

        Date now = Calendar.getInstance().getTime();
        if (this.isEmpty()) {
            this.insertAll(result, now, storeDbId.toString());
        } else {
            this.insertOrUpdateStatus(result, now, storeDbId.toString());
        }


    }

    private void insertAll(List<ContentValues> userBeerListIn, Date now, String storeDbId) {

//			List<ContentValues> bulkInsertBeers = new ArrayList<ContentValues>(userBeerListIn.size());
        List<ContentValues> bulkInsertBeers = userBeerListIn;
        List<ContentValues> bulkInsertStoreBeer = new ArrayList<ContentValues>(userBeerListIn.size());


        for (int i = 0; i < userBeerListIn.size(); i++) {
            ContentValues cvBeers = userBeerListIn.get(i);
            ContentValues cvStoresBeers = new ContentValues();

//				String currentToInsertBeerId = cvBeers.getAsString(Beers.BEER_ID);

            cvStoresBeers.put(Stores.StoreBeer.UPDATED_DATE, now.getTime());
            cvStoresBeers.put(Stores.StoreBeer.CREATION_DATE, now.getTime());
            cvStoresBeers.put(Stores.StoreBeer.ACTIVE, true);
            cvStoresBeers.put(Stores.StoreBeer.STORE_DB_ID, storeDbId);
//				cvStoresBeers.put(Beers.BEER_ID, currentToInsertBeerId );

            cvStoresBeers.remove(Beers.BEER_ID);

//				bulkInsertBeers.add(cvBeers);
            bulkInsertStoreBeer.add(cvStoresBeers);

        }

        int resBeers = this.mContentResolver.bulkInsert(Beers.CONTENT_URI, bulkInsertBeers.toArray(new ContentValues[]{}));

        Cursor q = this.mContentResolver.query(
                Beers.CONTENT_URI,
                Util.asAr(
                        Beers.BEER_ID,
                        Beers.BEERS_KEY
                ),
                null, null, BaseColumns._ID);
        ContentQueryMap ccc = new ContentQueryMap(q, Beers.BEER_ID, false, null);
        Map<String, ContentValues> previousMap = ccc.getRows();

        for (int i = 0; i < userBeerListIn.size(); i++) {
            ContentValues cvBeers = userBeerListIn.get(i);
            ContentValues cvStoresBeers = bulkInsertStoreBeer.get(i);

            String currentToInsertBeerId = cvBeers.getAsString(Beers.BEER_ID);
            Long currentToInsertBeerDbId = previousMap.get(currentToInsertBeerId).getAsLong(BaseColumns._ID);

            cvStoresBeers.put(Stores.StoreBeer.BEER_DB_ID, currentToInsertBeerDbId);
        }

        int resStoreBeer = this.mContentResolver.bulkInsert(Stores.StoreBeer.CONTENT_URI, bulkInsertStoreBeer.toArray(new ContentValues[]{}));

        String resString = String.format("resBeers: %d, ResStoreBeer: %d", resBeers, resStoreBeer);
        Log.d(TAG, resString);

        ccc.close();
        q.close();

        this.setOriginDate(now);

    }

    private void insertOrUpdateStatus(List<ContentValues> userBeerListIn, Date now, String storeDbId) {

        int beersUpdateRes = this.mContentResolver.bulkInsert(Beers.CONTENT_URI, userBeerListIn.toArray(new ContentValues[]{}));

        Cursor q = this.mContentResolver.query(
                Beers.CONTENT_URI,
                Util.asAr(
//						StoresPreferencesModel.StoreBeer.STORE_BEER_KEY,
                        Beers.BEER_ID,
//						StoresPreferencesModel.StoreBeer.BEER_DB_ID,
//						StoresPreferencesModel.StoreBeer.STORE_DB_ID
                        Beers.BEERS_KEY
                ),
                null, null, BaseColumns._ID);
        ContentQueryMap ccc = new ContentQueryMap(q, Beers.BEER_ID, false, null);
        Map<String, ContentValues> previousMap = ccc.getRows();

        List<ContentValues> bulkInsertStoreBeer = new ArrayList<ContentValues>();
        for (int i = 0; i < userBeerListIn.size(); i++) {
            ContentValues cvBeers = userBeerListIn.get(i);
            ContentValues cvStoresBeers = new ContentValues();


            String currentToInsertBeerId = cvBeers.getAsString(Beers.BEER_ID);
            Long currentToInsertBeerDbId = previousMap.get(currentToInsertBeerId).getAsLong(BaseColumns._ID);

//			if (now != null) {
//				//cv.put(MetaBeer.INTERNAL_DATE_ADDED, now.getTime());
//				cvStoresBeers.put(StoresPreferencesModel.Beers.MODIFIED, now.getTime());
//			}
            cvStoresBeers.put(Stores.StoreBeer.ACTIVE, true);
            cvStoresBeers.put(Stores.StoreBeer.STORE_DB_ID, storeDbId);
            cvStoresBeers.put(Stores.StoreBeer.BEER_DB_ID, currentToInsertBeerDbId);
            cvStoresBeers.put(Stores.StoreBeer.UPDATED_DATE, now.getTime());

            previousMap.remove(currentToInsertBeerId);

//			bulkInsertBeers.add(cvBeers);
            bulkInsertStoreBeer.add(cvStoresBeers);
        }

        List<Long> leftOverBeerIds = new ArrayList<Long>();
        for (Entry<String, ContentValues> cur : previousMap.entrySet()) {
            leftOverBeerIds.add(cur.getValue().getAsLong(BaseColumns._ID));
        }
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < leftOverBeerIds.size(); i++) {
            sb.append(leftOverBeerIds.get(i) + " , ");
        }
        if (sb.length() > 0 && sb.indexOf(",") > 0) {
            sb.setCharAt(sb.lastIndexOf(","), ' ');
        }

        ContentValues newCv = new ContentValues();
        newCv.put(Stores.StoreBeer.ACTIVE, false);
        newCv.put(Stores.StoreBeer.UPDATED_DATE, now.getTime());


//		Builder b = StoresPreferencesModel.StoreBeer.FILTER_CONTENT_URI.buildUpon();
//		b.appendQueryParameter(StoreBeer.STORE_DB_ID, storeDbId);

        int leftOverResult = this.mContentResolver.update(Stores.StoreBeer.CONTENT_URI, newCv, Stores.StoreBeer.STORE_DB_ID + " = ? AND " + Stores.StoreBeer.BEER_DB_ID + " IN (" + sb.toString() + ")", Util.asAr(storeDbId));


        //TODO
        //create new list with storedb id, and beer db id, active status?

        int beersStoresUpdateRes = this.mContentResolver.bulkInsert(Stores.StoreBeer.CONTENT_URI, bulkInsertStoreBeer.toArray(new ContentValues[]{}));


        ContentValues newCv2 = new ContentValues();
        newCv2.put(StoreBeer.CREATION_DATE, now.getTime());
        int createdBeers = this.mContentResolver.update(StoreBeer.CONTENT_URI, newCv2, StoreBeer.STORE_DB_ID + "=? AND " + "(" + StoreBeer.CREATION_DATE + " ISNULL)", Util.asAr(storeDbId));


        String resString = String.format("resBeers: %d, ResStoreBeer: %d, leftOverResult: %d", beersUpdateRes, beersStoresUpdateRes, leftOverResult);
        Log.d(TAG, resString);

    }


    public String getStoreDbId() {
        return storeDbId.toString();
    }

    public String getStoreUrl() {
        return storeUrl;
    }


    //Database Stuff
    public static final Long getStoreDbIdV2(Activity act, String url) {
        Cursor c1 = act.getContentResolver().query(Stores.CONTENT_URI, null, null, null, null);
//		DatabaseUtils.dumpCursor(c1);
        Cursor c = act.getContentResolver().query(Stores.CONTENT_URI, Util.asAr(Stores.STORES_KEY, Stores.URL), Stores.URL + " = ?", Util.asAr(url), Stores.URL + " desc");
        Long storeDbId = null;
        if (c.moveToFirst()) {
            storeDbId = c.getLong(c.getColumnIndex(BaseColumns._ID));
        }
        c.close();
        return storeDbId;
    }


    public static final Long getStoreDbId(ContentResolver mContentResolver2, String url) {
        Cursor c1 = mContentResolver2.query(Stores.CONTENT_URI, null, null, null, null);

        Cursor c = mContentResolver2.query(Stores.CONTENT_URI, Util.asAr(Stores.STORES_KEY, Stores.URL), Stores.URL + " = ?", Util.asAr(url), Stores.URL + " desc");
        Long storeDbId = null;
        if (c.moveToFirst()) {
            storeDbId = c.getLong(c.getColumnIndex(BaseColumns._ID));
        }
        c.close();
        return storeDbId;
    }

    public Long getStoreDbId(String url) {
        return this.storeDbId;
    }

    public Long getBeerDbId(String beerId) {
        Cursor c = mContentResolver.query(Beers.CONTENT_URI, Util.asAr(Beers.BEER_ID, Beers.BEERS_KEY), Beers.BEER_ID + "=?", Util.asAr(beerId), Beers.BEER_ID + " desc");
//		Lo storeUrl = c.getString(0);
//		DatabaseUtils.dumpCursor(c);
        c.moveToFirst();
        Long beerDbId = Long.valueOf(c.getString(c.getColumnIndex(BaseColumns._ID)));
        c.close();
        return beerDbId;

    }

    public Boolean isEmpty() {
        Builder b = Stores.StoreBeer.FILTER_CONTENT_URI.buildUpon();
//		b.appendQueryParameter(FlyingSaucerConv.ACTIVE_BY, "true");
        b.appendQueryParameter(FlyingSaucerConv.BY_STORE_DB_ID, getStoreDbId());

//		Uri curStoreDb = ContentUris.withAppendedId(StoresPreferencesModel.CONTENT_URI, storeDbId);
//		Uri uriStoresBeers = curStoreDb.buildUpon().appendEncodedPath("beers").build();
//		
        Cursor c = mContentResolver.query(b.build(), Util.asAr(StoreBeer.STORE_BEER_KEY, StoreBeer.STORE_DB_ID), null, null, null);//Util.asAr(StoresPreferencesModel.Beers.STORE_DB_ID)
        //DatabaseUtils.dumpCursor(c);

//		boolean ret = c.moveToFirst(); 
        boolean ret = c.getCount() <= 0;

        c.close();

        return ret;

    }

    @Override
    public Boolean needsRefresh() {
        //look up current refresh date
        //check if it's null or if it's expired
        //return result

        Boolean ret = false;

//		Builder b = StoresPreferencesModel.StoreBeer.FILTER_CONTENT_URI.buildUpon();
//		b.appendQueryParameter(FlyingSaucerConv.ACTIVE_BY, "true");
//		b.appendQueryParameter(FlyingSaucerConv.BY_STORE_DB_ID, getStoreDbId());


        Cursor c = this.mContentResolver.query(
                Stores.CONTENT_URI,
                Util.asAr(Stores.CREATION_DATE, Stores.STORES_KEY),
                BaseColumns._ID + "=?",
                Util.asAr(this.getStoreDbId()),
                BaseColumns._ID
        );

        if (!c.moveToFirst()) {
            ret = true;
            c.close();
            return ret;
        }
        String ds = c.getString(c.getColumnIndex(Stores.CREATION_DATE));
        c.close();
        if (ds == null) {
            ret = true;
            return ret;
        }
        Long d = Long.valueOf(ds);
        Date date = new Date();
        date.setTime(d);
        ret = Util.isTimeElapsed(date, 15);
        return ret;
    }

    public void setOriginDate(Date now) {
        ContentValues cv = new ContentValues();
        cv.put(Stores.CREATION_DATE, now.getTime());
        this.mContentResolver.update(Stores.withId(this.getStoreDbId()), cv, null, null);
    }


    public Boolean shouldCancel() {
/*		UfoClubApp app = (UfoClubApp) ((Activity) mContext).getApplication();
		BeersDownloader beersDownloader = app.getStoreBeersDownloader();
		if (beersDownloader != null) {
			if (beersDownloader.isCancelled()) {
				return true;
			}
		}*/
        //TODO FIX SHOULD CANCEL HERE
        return false;
    }


/*	@Override
    public BeersDownloader getDownloader(ListParentController controller) {
*//*		UfoClubApp app = (UfoClubApp) ((Activity) mContext).getApplication();
		
		BeersDownloader beersDownloader = app.getStoreBeersDownloader();
		if (beersDownloader == null) {
			beersDownloader = new BeersDownloader();
		}
		beersDownloader.setListParentController(controller);
		beersDownloader.setListModel(this);
		return beersDownloader;*//*
		
		UfoClubApp app = (UfoClubApp) ((Activity) mContext).getApplication();
		BeersDownloader beersDownloader = app.getStoreBeersDownloader();
		if (beersDownloader == null) {
			beersDownloader = new BeersDownloader();
		}	
		app.setStoreBeersDownloader(beersDownloader);
//		beersDownloader.setListParentController(controller);
//		beersDownloader.setListModel(this);
        //TODO FIX THIS ABOVE
		return beersDownloader;
	}*/

/*    @Override
    public void notifyListeners() {
        setChanged();
        notifyObservers();
    }*/


    public String getOriginDate() {
        String ret = null;

        Cursor q1 = this.mContentResolver.query(Stores.CONTENT_URI, Util.asAr(Stores.CREATION_DATE, Stores.STORES_KEY), BaseColumns._ID + "=?", Util.asAr(this.storeDbId), BaseColumns._ID);
        if (q1.moveToFirst()) {

            ret = q1.getString(q1.getColumnIndex(Stores.CREATION_DATE));
        }
        q1.close();
        return ret;
    }


    public Cursor getCursor() {
        Cursor ret = null;
//        Activity act = (Activity) controller.getParent();

        Builder b = Stores.StoreBeer.FILTER_CONTENT_URI.buildUpon();
        b.appendQueryParameter(FlyingSaucerConv.ACTIVE_BY, "true");
        b.appendQueryParameter(FlyingSaucerConv.BY_STORE_DB_ID, getStoreDbId());
        b.appendQueryParameter(FlyingSaucerConv.SORT_BY, Beers.NAME + " ASC");
        b.appendQueryParameter(FlyingSaucerConv.ADD_STANDARD_STORE_BEER_COLUMNS, "true");

        ret = mActivity.managedQuery(b.build(), null, null, null, null);

        return ret;
    }

    public Cursor getTreeCursor(String groupBy) {
        Cursor ret = null;
//        Activity act = (Activity) controller.getParent();
        Builder b = Stores.StoreBeer.FILTER_CONTENT_URI.buildUpon();
        b.appendQueryParameter(FlyingSaucerConv.ACTIVE_BY, "true");
        b.appendQueryParameter(FlyingSaucerConv.GROUP_BY, groupBy);
        b.appendQueryParameter(FlyingSaucerConv.BY_STORE_DB_ID, getStoreDbId());
        b.appendQueryParameter(FlyingSaucerConv.SORT_BY, groupBy + " ASC");

        String select = null;
        String[] selectArgs = null;
        if (groupBy.equals(StoreBeer.SIMPLE_CREATION_DATE)) {
            select = StoreBeer.CREATION_DATE + " != ?";
            selectArgs = Util.asAr(this.getOriginDate());
        }


        ret = mActivity.managedQuery(
                b.build(),
                Util.asArNonReduce(groupBy, Stores.StoreBeer.STANDARD_COLUMNS, Stores.StoreBeer.STORE_DB_ID),
                select,
                selectArgs,
                null
        );
        return ret;

        //TODO add case where this is the "new beers" list
    }


    private BeerUri beerUri = null;

    @Override
    public BeerUri getBeerUri() {
        return beerUri;
    }

    public Cursor getCursor(BeerUri beerUri) {
        Cursor cursor = null;
//        Activity act = (Activity) controller.getParent();
        Uri actualUri = beerUri.getUri(Stores.StoreBeer.FILTER_CONTENT_URI);

        cursor = mActivity.managedQuery(actualUri, null, null, null, null);
        return cursor;
    }

    public BeerUri getDefaultBeerUri() {
        BeerUri uri = new BeerUri();
        uri.sortBy = Beers.NAME + " asc";

        uri.isActive = true;

        uri.storeDbId = getStoreDbId();

        uri.addStoreBeer = true;

        return uri;
    }

    @Override
    public void setBeerUri(BeerUri beerUri) {
        this.beerUri = beerUri;
    }


    private static final List<Map<String, Object>> getUnfoldedBeerList(List<Map<String, Object>> result, String key) {
        List<Map<String, Object>> lm = new ArrayList<Map<String, Object>>(result.size());
        for (Map<String, Object> cvInner : result) {

            String rm = (String) cvInner.remove("Void");
            cvInner.put(key, rm);

            lm.add(cvInner);
        }
        return lm;
    }

    private static final String getStoreName(String storeUrl) {
        return RegexUtil.regexSingleMatchWithNull("stores\\/(.+?)\\/", null,
                storeUrl);
    }

    private static final void ActivityManageCursor(Context context, Cursor c) {
        Activity act = (Activity) context;
        act.startManagingCursor(c);
    }


//	@Override
//	public void setAsync(BeersDownloader async) {
//		((UfoClubApp)((Activity) mContext).getApplication()).setStoreBeersDownloader(async);
//	}


}
